package com.example.zluserservice.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.example.zluserservice.client.ResourceFeignClient;
import com.example.zluserservice.client.RoleFeignClient;
import com.example.zluserservice.common.annotation.OperationLog;
import com.example.zluserservice.common.constant.CommonConstant;
import com.example.zluserservice.common.constant.UserCacheConstant;
import com.example.zluserservice.common.exception.BaseException;
import com.example.zluserservice.common.util.IpUtil;
import com.example.zluserservice.common.util.JwtUtil;
import com.example.zluserservice.framework.mq.message.OperationLogMessage;
import com.example.zluserservice.framework.mq.producer.OperationLogProducer;
import com.example.zluserservice.framework.properties.JwtTokenManagerProperties;
import com.example.zluserservice.dto.request.LoginReqDTO;
import com.example.zluserservice.dto.UserAuth;
import com.example.zluserservice.dto.response.ResourceResDTO;
import com.example.zluserservice.dto.response.RoleResDTO;
import com.example.zluserservice.dto.response.UserResDTO;
import com.example.zluserservice.service.LoginService;
import com.example.zluserservice.service.remote.ResourceRemoteService;
import com.example.zluserservice.service.remote.RoleRemoteService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Author zhenliu（孙凌岳）
 * @Description 登录认证服务
 * @Date 2025/6/15 18:06
 * @Version 1.0
 */
@Service
@Slf4j
public class LoginServiceImpl implements LoginService {
    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private JwtTokenManagerProperties jwtTokenManagerProperties;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RoleRemoteService roleRemoteService;

    @Resource
    private ResourceRemoteService resourceRemoteService;

    /**
     * 用户服务 - 生成jwtToken和uuidToken 远程调用权限服务来认证
     *
     * @param loginReqDto
     * @param request
     * @return
     */
    @Override
    @OperationLog(action = "login",detail = "用户登录")
    public UserResDTO login(LoginReqDTO loginReqDto, HttpServletRequest request) {
        //使用认证管理器来进行认证
        UsernamePasswordAuthenticationToken upat = new UsernamePasswordAuthenticationToken(loginReqDto.getUsername(), loginReqDto.getPassword());
        Authentication authenticate = authenticationManager.authenticate(upat);
        if (!authenticate.isAuthenticated()) {
            throw new BaseException("用户登录失败");
        }
        //获取用户数据
        UserAuth userAuth = (UserAuth) authenticate.getPrincipal();
        UserResDTO userResDTO = BeanUtil.toBean(userAuth, UserResDTO.class);

        //远程调用权限服务获取信息
        //获取用户的资源列表
        // GET/user/current-user
        //调用带熔断降级的包装类
        List<ResourceResDTO> resourceResDTOList = resourceRemoteService.findResourceResDTOListByUserId(userResDTO.getId());
//        log.info(resourceResDTOListByUserId.toString());
        Set<String> resourceRequestPaths = resourceResDTOList.stream()
                .filter(r -> "r".equals(r.getResourceType()))
                .map(ResourceResDTO::getRequestPath)
                .collect(Collectors.toSet());
        userResDTO.setResourceRequestPaths(resourceRequestPaths);

        //获取用户的角色列表
        //调用带熔断降级的包装类
        List<RoleResDTO> roleResDTOList = roleRemoteService.findRoleResDTOListByUserId(userResDTO.getId());
        Set<String> roleLabels = roleResDTOList.stream()
                .map(RoleResDTO::getLabel)
                .collect(Collectors.toSet());
        userResDTO.setRoleLabels(roleLabels);
        userResDTO.setRoleList(roleResDTOList);

        //生成token jwtToken uuidToken(userToken)
        //jwtToken用来认证授权  uuidToken用来把会话和uuid绑定 保证只有一个会话登录
        String uuidToken = UUID.randomUUID().toString();
        userResDTO.setUserToken(uuidToken);

        //敏感数据过滤
        userResDTO.setPassword("");

        Map<String, Object> claims = new HashMap<>();
        claims.put(CommonConstant.CURRENT_USER, JSONUtil.toJsonStr(userResDTO));

//        log.info(jwtTokenManagerProperties.getBase64EncodedSecretKey());

        String jwtToken = JwtUtil.createJWT(jwtTokenManagerProperties.getBase64EncodedSecretKey()
                , jwtTokenManagerProperties.getTtl(), claims);

        //过期时间计算
        long ttl = Long.valueOf(jwtTokenManagerProperties.getTtl() / 1000);

        //构建userToken的key
        String userTokenKey = UserCacheConstant.USER_TOKEN + userResDTO.getUsername();

        stringRedisTemplate.opsForValue().set(userTokenKey, uuidToken, ttl, TimeUnit.SECONDS);

        String jwtTokenKey = UserCacheConstant.JWT_TOKEN + uuidToken;

        stringRedisTemplate.opsForValue().set(jwtTokenKey, jwtToken, ttl, TimeUnit.SECONDS);

        return userResDTO;
    }
}
